/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package compiler.scanner.nfa;

import java.util.Set;

/**
 * utils to be called from the antlr RE tree parser
 * @author meemo
 */
public class NFAUtils
{
    //~ Methods ----------------------------------------------------------------

    public static NFAItem cat(NFAItem start, NFAItem end)
    {
        // don't do anything if already catted
        if (eTransExists(start.getEndState(), end.getStartState()))
            return start;

        NFAItem     ret = new NFAItem(start.getStartState(), end.getEndState());
        ETransition trans = new ETransition();
        start.getEndState().getTransitions().add(trans);
        trans.getDestinations().add(end.getStartState());

        return ret;
    }

    public static NFAItem kleen(NFAItem item)
    {
        NFAState    startState = new NFAState();
        NFAState    endState = new NFAState();

        ETransition transToLoop = new ETransition();
        transToLoop.getDestinations().add(item.getStartState());

        ETransition transToEscape = new ETransition();
        transToEscape.getDestinations().add(endState);

        if (!eTransExists(startState, item.getStartState()))
            startState.getTransitions().add(transToLoop);

        if (!eTransExists(startState, endState))
            startState.getTransitions().add(transToEscape);

        ETransition transToLoop2 = new ETransition();
        transToLoop2.getDestinations().add(item.getStartState());

        ETransition transToEscape2 = new ETransition();
        transToEscape2.getDestinations().add(endState);

        if (!eTransExists(item.getEndState(), endState))
            item.getEndState().getTransitions().add(transToEscape2);

        if (!eTransExists(item.getEndState(), item.getStartState()))
            item.getEndState().getTransitions().add(transToLoop2);

        NFAItem newItem = new NFAItem(startState, endState);

        return newItem;
    }

    public static NFAItem or(NFAItem item1, NFAItem item2)
    {
        NFAState startState = new NFAState();
        NFAState endState = new NFAState();

        if (!eTransExists(startState, item1.getStartState()))
        {
            ETransition transStartToItem1 = new ETransition();
            transStartToItem1.getDestinations().add(item1.getStartState());
            startState.getTransitions().add(transStartToItem1);
        }

        if (!eTransExists(startState, item2.getStartState()))
        {
            ETransition transStartToItem2 = new ETransition();
            transStartToItem2.getDestinations().add(item2.getStartState());
            startState.getTransitions().add(transStartToItem2);
        }

        ETransition transToEndState = new ETransition();
        transToEndState.getDestinations().add(endState);

        if (!eTransExists(item1.getEndState(), endState))
            item1.getEndState().getTransitions().add(transToEndState);

        if (!eTransExists(item2.getEndState(), endState))
            item2.getEndState().getTransitions().add(transToEndState);

        NFAItem newItem = new NFAItem(startState, endState);

        return newItem;
    }

    public static void transOn(NFAState start, NFAState end, char c)
    {
        NFATransition trans = new NFATransition();
        start.getTransitions().add(trans);
        trans.setCharacter(c);
        trans.getDestinations().add(end);
    }

    public static void transOn(NFAState start, NFAState end, NFAItem item)
    {
        if (!eTransExists(start, item.getStartState()))
        {
            ETransition trans = new ETransition();
            start.getTransitions().add(trans);
            trans.getDestinations().add(item.getStartState());
        }

        if (!eTransExists(item.getEndState(), end))
        {
            ETransition trans = new ETransition(); // a.end -> E -> end
            item.getEndState().getTransitions().add(trans);
            trans.getDestinations().add(end);
        }
    }

    public static void transOn(NFAState start, NFAState end, Set<Character> set)
    {
        for (Character c : set)
        {
            transOn(start, end, c);
        }
    }

    private static boolean eTransExists(NFAState endState, NFAState startState)
    {
        for (NFATransition trans : endState.getTransitions())
        {
            if (trans instanceof ETransition)
            {
                for (NFAState dest : trans.getDestinations())
                {
                    if (dest.equals(startState))
                        return true;
                }
            }
        }

        return false;
    }
}
